import axios, { AxiosRequestConfig, AxiosResponse } from 'axios'
import NProgress from '@/utils/nprogress' // progress bar
import { useUserStore } from '@/store/user'
import { useGlobalStore } from '@/store/global'
import { getOauth, setOauth } from '../auth'

import { errorHandler } from './helper'
import { IResponse, IListResponse } from './typing'

import { refreshToken, refreshToken2 } from '@/api/user'

/**
 * 配置request请求时的默认参数
 */
const request = axios.create({
  // baseURL: baseURL,
  // withCredentials: true, // 当跨域请求时发送cookie
  timeout: 60 * 1000, // 请求超时时间,60 * 1000(单位毫秒) / 0 不做限制
})

/**
 * 请求前
 * 请求拦截器
 */
request.interceptors.request.use(
  async (config: AxiosRequestConfig & { cType?: boolean }) => {
    const userStore = useUserStore()

    if (config.headers) {
      // 如果设置了cType 说明是自定义 添加 Content-Type类型 为自定义post 做铺垫
      if (config['cType']) {
        config.headers['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'
      }

      const oauth = await getOauth()

      if (!!oauth && oauth.expires_at >= new Date().getTime()) {
        config.headers['Authorization'] = `${oauth.token_type} ${oauth.access_token}`
      }
    }
    NProgress.start()
    return config
  }
  /* error=> {} */ // 已在 export default catch
)

/**
 * 请求后
 * 响应拦截器
 */
// 重试队列，每一项将是一个待执行的函数形式
request.interceptors.response.use(
  async (response: AxiosResponse) => {
    NProgress.done()
    const userStore = useUserStore()
    const res: IResponse<any> | IListResponse<any> = response.data

    // 自定义状态码验证
    if (!res.success && res.code) {
      if (res.code == '4001' || res.code == '4002' || res.code == '1000') {
        //1.刷新token时要暂停所有请求, 等待token刷新
        //2.多个请求刷新token时, 只能执行一个, 其余等待
        const reReConf = response.config
        const oauth = getOauth()
        if (!useGlobalStore().isRefreshToken) {
          useGlobalStore().isRefreshToken = true
          return refreshToken2(oauth.refresh_token)
            .then((data2) => {
              const { data: refreshOauth } = data2.data
              userStore.oauth = refreshOauth
              setOauth(refreshOauth)
              useGlobalStore().isRefreshToken = false
              // 已经刷新了token，将所有队列中的请求进行重试
              useGlobalStore().requestsList.forEach((cb) => cb())
              // 重试完了别忘了清空这个队列（掘金评论区同学指点）
              useGlobalStore().requestsList = []
              return request(reReConf)
            })
            .catch((res) => {
              console.error('refreshtoken error =>', res)
              window.location.href = '/'
            })
            .finally(() => {
              useGlobalStore().isRefreshToken = false
            })
        } else {
          // 正在刷新token，返回一个未执行resolve的promise
          return new Promise((resolve) => {
            // 将resolve放进队列，用一个函数形式来保存，等token刷新后直接执行
            useGlobalStore().requestsList.push(() => {
              resolve(request(reReConf))
            })
          })
        }
      } else {
        return Promise.reject({
          response,
          errorType: 'CustomError',
        })
      }
    }
    return res as any
  }
  /* error => {} */ // 已在 export default catch
)

/**
 * axios 导出
 *
 * Method: get
 *     Request Headers
 *         无 - Content-Type
 *     Query String Parameters
 *         name: name
 *         age: age
 *
 * Method: post
 *     Request Headers
 *         Content-Type:application/json;charset=UTF-8
 *     Request Payload
 *         { name: name, age: age }
 *         Custom config parameters
 *             { cType: true }  Mandatory Settings Content-Type:application/json;charset=UTF-8
 * ......
 */
export default function (config: AxiosRequestConfig): any {
  return request(config)
    .then((response: AxiosResponse) => response)
    .catch((error) => errorHandler(error))
}
